#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> //sockaddr_in
#include <arpa/inet.h> //inet_addr
#include "mylog.hpp"

#define SIZE 1024
Log lg;
static const std::string defaultip = "0.0.0.0";

enum{
    SOCKETERR = 1,
    BINDERR
};

class udp_server
{
public:
    udp_server(const uint16_t& port,const std::string& ip = defaultip)
        :_sockfd(-1)
        ,_ip(ip)
        ,_port(port)
    {}
    ~udp_server()
    {
        if(_sockfd > 0) close(_sockfd);
    }
    void initserver()
    {

        _sockfd = socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd == -1)
        {
            lg(FATAL,"套接字申请失败,errno:%d",errno);
            exit(SOCKETERR);
        }
        lg(INFO,"套接字申请成功,errno:%d",errno);

        struct sockaddr_in local;
        bzero(&local,sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = inet_addr(_ip.c_str());


        socklen_t len = sizeof(local);
        if(bind(_sockfd,(const sockaddr *)(&local),len) < 0)
        {
            lg(FATAL,"绑定失败,errno:%d",errno);
            exit(BINDERR);
        }
        lg(INFO,"绑定成功,errno:%d",errno);
    }

    void run()
    {
        
        char buf[SIZE];
        while(true)
        {
            struct sockaddr_in addr;
            bzero(&addr,sizeof(addr));
            socklen_t len = sizeof(addr);
            ssize_t ret = recvfrom(_sockfd,buf,sizeof(buf) - 1, 0,(sockaddr *)(&addr),&len);//MSG_DONTWAIT 非阻塞
            if(ret == -1)
            {
                lg(WARNING,"接收数据失败,errno:%d",errno);
                continue;
            }

            buf[ret] = 0;

            std::string info = buf;
            info += "服务端已处理";

            //发回客户端
            ssize_t n = sendto(_sockfd,info.c_str(),info.size(),0,(const sockaddr *)(&addr),len);
            if(n == -1)
            {
                lg(WARNING,"发送数据失败,errno:%d",errno);
                continue;
            }

        }
    }
private:
    int _sockfd;//网络文件描述符,调用sockset
    std::string _ip;//ip
    uint16_t _port;//端口

};